use std::{
    fs,
    path::{Path, PathBuf},
    process::Command,
    sync::{Arc, Mutex},
};

use tokio::join;
use video_img_find::video_cap::{self, find_img_pos_ms};

#[tokio::test]
async fn cut() -> anyhow::Result<()> {
    let dir_path = "/home/jaakan/下载/超级飞侠9";

    // let arc_list = Arc::new(Mutex::new(Vec::<(String, Option<f64>)>::new()));

    let mut tasks = Vec::<_>::new();

    for i in 1..=20 {
        let name = format!("{0:>0width$}.mp4", i, width = 2);
        let path = format!("{dir_path}/{name}");
        // let _arc_list = arc_list.clone();
        let task = tokio::spawn(async move {
            // 跳过时间
            let skip_ms = 60_000f64;
            let pos_ms =
                video_cap::find_img_pos_ms(path.as_str(), "./target.jpg", skip_ms, None).unwrap();

            // list.push(path);
            // let mut _list = _arc_list.lock().unwrap();
            // _list.push(("".to_string(), pos_ms));

            (path, pos_ms)
        });
        tasks.push(task);
    }

    let res = futures::future::join_all(tasks).await;
    println!("{res:?}");

    Ok(())
}

#[tokio::test]
async fn test_video_cut() {
    let video_path_str = "/home/jaakan/下载/超级飞侠9/14.mp4".to_string();
    let target_img_str = "/home/jaakan/workspace/rust/video_img_find/target.jpg";

    let video_path = Path::new(video_path_str.as_str());
    if !video_path.exists() {
        eprintln!("视频文件不存在!");
        return;
    }

    let dir = video_path.parent().unwrap();

    let file_name = video_path
        .file_name()
        .unwrap()
        .to_string_lossy()
        .to_string();

    println!("[video_path]: {}", video_path.to_string_lossy().to_string());
    println!("[dir]: {}", dir.to_string_lossy().to_string());
    println!("[file_name]: {}", file_name);

    // 跳过时间
    let skip_ms = 60_000f64;
    let pos_ms = find_img_pos_ms(&video_path_str, target_img_str, skip_ms, None).unwrap();

    if pos_ms.is_none() {
        ()
    }

    let out_dir = dir.join("output");
    if !&out_dir.exists() {
        fs::create_dir(&out_dir).unwrap();
    }

    // 生成视频输入文件
    let (list_file, part0, part1) = generate_list_file(&out_dir, &file_name);
    println!("[list_file]: {:?}", &list_file.to_string_lossy());

    let cmd = format!(
        "ffmpeg -ss 0.0 -to '{}ms' -i '{}' -y -f mp4 -vcodec copy -acodec copy -q:v 1 '{}'",
        pos_ms.unwrap(),
        video_path.to_string_lossy(),
        part0.to_string_lossy(),
    );

    println!("{cmd}");
    exec_command(&cmd);

    let pos_ms = pos_ms.unwrap() + 19_000_f64;
    let cmd = format!(
        "ffmpeg -ss '{}ms' -i '{}' -y -f mp4 -vcodec copy -acodec copy -q:v 1 '{}'",
        pos_ms,
        video_path.to_string_lossy(),
        part1.to_string_lossy(),
    );
    println!("{cmd}");
    exec_command(&cmd);

    // 输出视频文件
    let output_vide_file = out_dir.join(file_name.as_str());
    let cmd = format!(
        "ffmpeg -f concat -safe 0 -i '{}' -acodec copy -vcodec copy '{}'",
        &list_file.to_string_lossy(),
        output_vide_file.to_string_lossy(),
    );
    println!("{cmd}");
    exec_command(&cmd);

    fs::remove_file(part0).unwrap();
    fs::remove_file(part1).unwrap();
    fs::remove_file(list_file).unwrap();
}

fn generate_list_file(output_dir: &PathBuf, file_name: &str) -> (PathBuf, PathBuf, PathBuf) {
    let src_file_name = format!("{}.txt", file_name);
    let video_src_file = &output_dir.join(src_file_name.as_str());

    let part_file_0 = &output_dir.join(format!("{}_part_0.mp4", file_name));
    let part_file_1 = &output_dir.join(format!("{}_part_1.mp4", file_name));

    exec_command(
        format!(
            "echo 'file {}' > {}",
            part_file_0.to_string_lossy(),
            video_src_file.to_string_lossy()
        )
        .as_str(),
    );
    exec_command(
        format!(
            "echo 'file {}' >> {}",
            part_file_1.to_string_lossy(),
            video_src_file.to_string_lossy()
        )
        .as_str(),
    );

    (
        video_src_file.clone(),
        part_file_0.clone(),
        part_file_1.clone(),
    )
}

fn exec_command(cmd: &str) {
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .expect("Failed to execute command");
}
